package log

import (
	"fmt"
	"strings"

	"runtime"
	"time"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"gopkg.in/natefinch/lumberjack.v2"
)

var glogger *zap.Logger

// logpath 日志文件路径
// loglevel 日志级别
func Init(logpath, loglevel, serviceName string) {

	hook := lumberjack.Logger{
		Filename:   logpath, // 日志文件路径
		MaxSize:    1024,    // megabytes
		MaxBackups: 30,      // 最多保留备份个数
		MaxAge:     30,      // days
		Compress:   true,    // 是否压缩 disabled by default

	}
	w := zapcore.AddSync(&hook)

	var level zapcore.Level
	switch loglevel {
	case "debug":
		level = zap.DebugLevel
	case "info":
		level = zap.InfoLevel
	case "error":
		level = zap.ErrorLevel
	default:
		level = zap.InfoLevel
	}

	core := zapcore.NewCore(
		zapcore.NewConsoleEncoder(zapcore.EncoderConfig{
			MessageKey:    "msg",
			LevelKey:      "level",
			TimeKey:       "ts",
			CallerKey:     "caller",
			StacktraceKey: "trace",
			LineEnding:    zapcore.DefaultLineEnding,
			EncodeLevel:   zapcore.CapitalLevelEncoder,
			EncodeCaller:  zapcore.ShortCallerEncoder,
			EncodeTime: func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
				enc.AppendString(t.Format("2006-01-02 15:04:05.000"))
			},
			EncodeDuration: zapcore.SecondsDurationEncoder,
		}),
		w,
		level,
	)

	// 开启开发模式，堆栈跟踪
	//caller := zap.AddCaller()
	// 开启文件及行号
	//development := zap.Development()
	// 设置初始化字段
	/*filed := zap.Fields(zap.String("serviceName", serviceName))
	if len(serviceName) == 0 {
		filed = nil
	}*/

	glogger = zap.New(core)
	glogger.Info("DefaultLogger init success")

	return
}

func formatLog(src string, f interface{}, v ...interface{}) string {
	var msg string
	switch f.(type) {
	case string:
		msg = f.(string)
		if len(v) == 0 {
			return src + msg
		}
		if strings.Contains(msg, "%") && !strings.Contains(msg, "%%") {
			//format string
		} else {
			//do not contain format char
			msg += strings.Repeat(" %v", len(v))
		}
	default:
		msg = fmt.Sprint(f)
		if len(v) == 0 {
			return src + msg
		}
		msg += strings.Repeat(" %v", len(v))
	}
	src += msg

	return fmt.Sprintf(src, v...)
}

func Debug(f interface{}, v ...interface{}) {

	pc, _, lineno, ok := runtime.Caller(1)
	src := ""
	if ok {
		src = fmt.Sprintf("(%s:%d)  ", runtime.FuncForPC(pc).Name(), lineno)
	}
	glogger.Sugar().Debug(formatLog(src, f, v...))
}

func Info(f interface{}, v ...interface{}) {
	pc, _, lineno, ok := runtime.Caller(1)
	src := ""
	if ok {
		src = fmt.Sprintf("(%s:%d)  ", runtime.FuncForPC(pc).Name(), lineno)
	}
	glogger.Sugar().Info(formatLog(src, f, v...))
}

func Warn(f interface{}, v ...interface{}) {

	pc, _, lineno, ok := runtime.Caller(1)
	src := ""
	if ok {
		src = fmt.Sprintf("(%s:%d)  ", runtime.FuncForPC(pc).Name(), lineno)
	}
	glogger.Sugar().Warn(formatLog(src, f, v...))
}

func Error(f interface{}, v ...interface{}) {
	pc, _, lineno, ok := runtime.Caller(1)
	src := ""
	if ok {
		src = fmt.Sprintf("(%s:%d)  ", runtime.FuncForPC(pc).Name(), lineno)
	}
	glogger.Sugar().Error(formatLog(src, f, v...))
}

func Panic(f interface{}, v ...interface{}) {
	pc, _, lineno, ok := runtime.Caller(1)
	src := ""
	if ok {
		src = fmt.Sprintf("(%s:%d)  ", runtime.FuncForPC(pc).Name(), lineno)
	}
	glogger.Sugar().Panic(formatLog(src, f, v...))
}
